<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>

  <body>
    <div class="a">手写Promise</div>
  </body>
  <script>
    // promiseA+ 规范 https://promisesaplus.com/#point-1
    // 在规范里面规定 只要有then方法 那么你就是一个promise对象 哪怕你是个对象 哪怕你是一个函数
    const PENDING = "pending";
    const FULFILLED = "fulfilled";
    const REJECTED = "rejected";
    class MyPromise {
      // 私有化内部变了 1是使用symbol
      // static PENDING = Symbol("pending");
      // static FULFILLED = Symbol("fulfilled");
      // static REJECTED = Symbol("rejected");
      // 2是使用新语法#号
      #state = "pending";
      #result = undefined;
      #handlers = [];
      /**
       * 构造函数，创建一个新的 MyPromise 实例。
       * @param {Function} executor - 执行器函数，接收 resolve 和 reject 两个参数。
       */
      constructor(executor) {
        const resolve = (data) => {
          this.#changeState(FULFILLED, data);
        };
        const reject = (reason) => {
          this.#changeState(REJECTED, reason);
        };
        // 定义属性 pending 进行中 fulfilled成功 rejected失败 //https://es6.ruanyifeng.com/#docs/promise
        // try是为了当在Promise里面使用throw new Error("错误111");返回错误的时候 我们进行捕获 并抛出去
        // 只能捕获同步代码的报错 异步的无法捕获 官方也没办法
        try {
          // executor 是一个函数，调用时会自动执行，并传入两个函数作为参数，分别表示异步操作成功和失败。
          // https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise/Promise
          executor(resolve, reject);
        } catch (error) {
          reject(error);
        }
      }

      /**
       * 改变 Promise 的状态。
       * @param {string} state - 新的状态，可以是 PENDING, FULFILLED 或 REJECTED。
       * @param {*} result - 与状态相关的结果或原因。
       * @private
       */
      #changeState(state, result) {
        // 状态只能改变一次
        if (this.#state === PENDING) {
          this.#state = state;
          this.#result = result;
          this.#runHandler();
        } else {
          console.warn("状态只能改变一次");
          return;
        }
      }
      /**
       * 运行一个处理函数。
       * @param {Function} callback - 要执行的回调函数。
       * @param {Function} resolve - 用于解决新 Promise 的 resolve 函数。
       * @param {Function} reject - 用于拒绝新 Promise 的 reject 函数。
       * @private
       */
      #runOneHandler(callback, resolve, reject) {
        this.#runMicroTask(() => {
          // 如果then方法传递的是一个函数，那么就执行这个函数，并且把结果传递给下一个then方法
          if (typeof callback !== "function") {
            // 捕获传递的函数执行能不能成功
            const settled = this.#state === FULFILLED ? resolve : reject;
            settled(this.#result);
            return;
          } else {
            // 当then传递的不是一个方法 但是promise执行成功了
            try {
              // 如果传入的参数不是函数的话，那then返回的Promise就穿透了，状态与调用then的Promise实例状态一致
              const result = callback(this.#result);
              // resolve(result);
              if (this.#isPromise(result)) {
                result.then(resolve, reject);
              } else {
                resolve(result);
              }
            } catch (error) {
              reject(error);
            }
          }
        });
      }
      /**
       * 判断一个值是否为 Promise。
       * @param {*} value - 要判断的值。
       * @returns {boolean} - 如果值是 Promise 则返回 true，否则返回 false。
       * @private
       */
      #isPromise(value) {
        return (
          typeof value === "object" ||
          (typeof value === "function" &&
            value !== null &&
            typeof value.then === "function")
        );
      }
      /**
       * 运行一个微任务。
       * @param {Function} func - 要执行的微任务函数。
       * @private
       */
      #runMicroTask(func) {
        // 模拟微任务
        // 我们在这可以分node环境和浏览器环境
        if (
          typeof process === "object" &&
          typeof process.nextTick === "function"
        ) {
          // nextTick 是node事件循环里面微队列
          process.nextTick(func);
        } else if (typeof MutationObserver === "function") {
          const ob = new MutationObserver(func);
          const text = document.createTextNode("1");
          ob.observe(text, { characterData: true });
          text.data = text.data ? 0 : 1;
        } else if (typeof setImmediate === "function") {
          setImmediate(func);
        } else {
          setTimeout(func, 0);
        }
      }
      /**
       * 运行所有已注册的处理函数。
       * @private
       */
      #runHandler() {
        if (this.#state === PENDING) return;
        if (this.#handlers.length === 0) {
          // 如果没有then方法，那么就直接返回
          return;
        }
        while (this.#handlers.length) {
          // 每次都取第一个执行
          const { onFulfilled, onRejected, resolve, reject } =
            this.#handlers.shift();
          if (this.#state === FULFILLED) {
            // 如果是成功状态
            // 如果then方法没有传递参数，那么就直接返回
            this.#runOneHandler(onFulfilled, resolve, reject);
          }
          if (this.#state === REJECTED) {
            // 如果是失败状态
            // 如果then方法没有传递参数，那么就直接返回
            this.#runOneHandler(onRejected, resolve, reject);
          }
        }
      }
      /**
       * 注册成功和失败的回调函数。
       * @param {Function} onFulfilled - 成功时的回调函数。
       * @param {Function} onRejected - 失败时的回调函数。
       * @returns {MyPromise} - 返回一个新的 MyPromise 实例。
       */
      then(onFulfilled, onRejected) {
        return new MyPromise((resolve, reject) => {
          // 这是为了如果是异步调用的时候，来进行执行
          this.#handlers.push({
            onFulfilled,
            onRejected,
            resolve,
            reject,
          });
          this.#runHandler();
        });
      }
      /**
       * 注册失败的回调函数。
       * @param {Function} onRejected - 失败时的回调函数。
       * @returns {MyPromise} - 返回一个新的 MyPromise 实例。
       */
      catch(onRejected) {
        return this.then(null, onRejected);
      }
      /**
       * 注册无论成功还是失败都会执行的回调函数。
       * @param {Function} callback - 要执行的回调函数。
       * @returns {MyPromise} - 返回一个新的 MyPromise 实例。
       */
      finally(callback) {
        return this.then(
          (value) => {
            callback(value);
            return value;
          },
          (reason) => {
            callback(reason);
            throw reason;
          }
        );
      }

      /**
       * 注册失败的回调函数（与 catch 方法相同）。
       * @param {Function} callback - 失败时的回调函数。
       * @returns {MyPromise} - 返回一个新的 MyPromise 实例。
       */
      reject(callback) {
        return this.then(null, callback);
      }
      /**
       * 等待所有 Promise 都成功或有一个失败。
       * @param {Array<MyPromise>} promises - 要等待的 Promise 数组。
       * @returns {MyPromise} - 返回一个新的 MyPromise 实例。
       */
      all(promises) {
        return new MyPromise((resolve, reject) => {
          const result = [];
          let count = 0;
          promises.forEach((promise) => {
            promise.then(
              (res) => {
                result.push(res);
                if (result.length === promises.length) {
                  resolve(result);
                }
              },
              (err) => {
                reject(err);
              }
            );
          });
          // 如果是空的 里面没有迭代器 直接返回
          if (promises.length === 0) {
            resolve(result);
          }
        });
      }
      /**
       * 等待第一个 Promise 完成（成功或失败）。
       * @param {Array<MyPromise>} promises - 要等待的 Promise 数组。
       * @returns {MyPromise} - 返回一个新的 MyPromise 实例。
       */
      race(promises) {
        return new MyPromise((resolve, reject) => {
          promises.forEach((promise) => {
            promise.then(resolve, reject);
          });
        });
      }
      /**
       * 等待至少一个 Promise 成功，如果所有都失败则返回 AggregateError。
       * @param {Array<MyPromise>} promises - 要等待的 Promise 数组。
       * @returns {MyPromise} - 返回一个新的 MyPromise 实例。
       */
      any(promises) {
        // resolve必须等到有一个成功的结果
        // reject所有的都失败才执行reject
        const reasons = [];
        return new MyPromise((resolve, reject) => {
          promises.forEach((promise) => {
            promise.then(resolve, (err) => {
              reasons.push(err);
              if (reasons.length === promises.length) {
                reject(new AggregateError(reasons));
              }
            });
          });
        });
      }
    }
    const proCeshi = new MyPromise((resolve, reject) => {
      setTimeout(() => {
        resolve(1);
      }, 100);
    });
    proCeshi.reject((e) => {
      console.log("1", e);
    });

    proCeshi.then(
      () => {
        console.log("成功2");
      },
      (err) => {
        console.log("失败2", err);
      }
    );

    const pro = new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve(1);
      }, 100);
    });
    console.log(pro);
  </script>
  <style>
    .a {
      color: rgba(0, 17, 255, 0.418);
    }
  </style>
</html>
